import type { AxiosRequestConfig, AxiosError } from 'axios';
import axios, { AxiosResponse } from 'axios';
import { getToken } from '@/utils/auth';
import type { ResponseBody } from '@/api/typing';
import { Notification as notification } from '@arco-design/web-vue';

// 这里是用于设定请求后端时，所用的 Token KEY
// 可以根据自己的需要修改，常见的如 Access-Token，Authorization
// 需要注意的是，请尽量保证使用中横线`-` 来作为分隔符，
// 避免被 nginx 等负载均衡器丢弃了自定义的请求头
export const REQUEST_TOKEN_KEY = 'Authorization';

// 创建 axios 实例
const request = axios.create({
  // API 请求的默认前缀
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 6000, // 请求超时时间
});
export type RequestError = AxiosError<{
  error_code?: string;
  data?: any;
  error_message?: string;
}>;

const toLogin = () => {
  let loginPath =
    import.meta.env.VITE_APP_PUBLIC_PATH === '/'
      ? ''
      : import.meta.env.VITE_APP_PUBLIC_PATH;
  loginPath += '/login';
  if (window.location.pathname === loginPath) {
    return;
  }
  window.location.href = `${window.location.protocol}//${window.location.host}${loginPath}`;
};

// 异常拦截处理器
const errorHandler = (error: RequestError): Promise<any> => {
  let message = '';
  if (error.response) {
    const { data = {}, status, statusText } = error.response;
    message = (data && data.error_message) || statusText;
    // 403 无权限
    if (status === 403) {
      notification.error({
        title: 'Forbidden',
        content: message,
      });
      toLogin();
    } else if (status === 404) {
      notification.error({
        title: 'Forbidden',
        content: message,
      });
    } else if (status === 401) {
      // 401 未登录/未授权
      notification.error({
        title: 'Unauthorized',
        content: message,
      });
      // 如果你需要直接跳转登录页面
      // location.replace(
      //   `${process.env.VUE_APP_PUBLIC_PATH} + ${loginRoutePath}`.replaceAll('//', '/'),
      // );
      toLogin();
    } else {
      message = '服务器连接失败，请刷新重试';
    }
    error.code = status.toString();
    error.message = message;
    return Promise.reject(error);
  }
  error.code = '500';
  error.message = '服务器连接失败，请刷新重试';
  return Promise.reject(error);
};

// 请求拦截器
const requestHandler = (
  config: AxiosRequestConfig
): AxiosRequestConfig | Promise<AxiosRequestConfig> => {
  const savedToken = getToken();
  // 如果 token 存在
  // 让每个请求携带自定义 token, 请根据实际情况修改
  if (!config.headers) {
    config.headers = {};
  }
  if (savedToken) {
    config.headers[REQUEST_TOKEN_KEY] = `Bearer ${savedToken}`;
  }
  return config;
};

// Add a request interceptor
request.interceptors.request.use(requestHandler, errorHandler);

// 响应拦截器
const responseHandler = (
  response: AxiosResponse<ResponseBody<any>>
): Promise<any> => {
  return new Promise((resolve, reject) => {
    const { status, config, data: result } = response;
    if (status !== 200) {
      reject(new Error('服务器连接失败，请刷新重试！'));
      return;
    }
    if (
      config.responseType === 'blob' ||
      config.responseType === 'stream' ||
      config.responseType === 'arraybuffer' ||
      config.responseType === 'document'
    ) {
      resolve(response.data);
      return;
    }
    /**
     * If token is either expired, not provided or invalid
     * then redirect to login. On server side the error
     * messages can be changed on app/Providers/EventServiceProvider.php
     */
    if (
      result &&
      result.code &&
      result.code !== 200 &&
      response.config.url !== '/api/member/auth/logout'
    ) {
      if (result.code === 401) {
        toLogin();
        reject(new Error('登录已失效，请重新登录！'));
        return;
      }
      if (result.code === 404) {
        reject(new Error('接口未找到！'));
        return;
      }
      reject(new Error(result.message));
      return;
    }
    resolve(response.data);
  });
};

// Add a response interceptor
request.interceptors.response.use(responseHandler, errorHandler);

export { AxiosResponse };

export default request;
